<template>
  <div id="Curvefit">
    <!-- {{variables}} -->
    <el-header style="text-align:center">
      <h1>曲线拟合工具箱</h1>
    <!-- {{variables}} -->
    </el-header>
    <el-row :gutter="40" type="flex" justify="space-around">
      <el-col :span="8">
        <el-form ref="form" :model="form" label-width="80px">
          <h2>拟合输入</h2>
          <el-divider content-position="left">拟合数据</el-divider>
          <el-form-item label="拟合数据x">
            <el-select v-model="form.xdata" placeholder="请选择拟合数据x" @change="plotdot">
              <div v-for="(item, index) in variables" :key="index">
                <el-option v-if="matchState(item.Type)" :value="item.value" :label="item.Name">{{ item.Name }}</el-option>
              </div>
            </el-select>
          </el-form-item>
          <el-form-item label="拟合数据y">
            <el-select v-model="form.ydata" placeholder="请选择拟合数据y" @change="plotdot">
              <div v-for="(item, index) in variables" :key="index">
                <el-option v-if="matchState(item.Type)" :value="item.value" :label="item.Name">{{ item.Name }}</el-option>
              </div>
            </el-select>
          </el-form-item>
          <el-divider content-position="left">拟合模型</el-divider>
          <el-form-item label="拟合类型">
            <el-col :span="10">
              <el-select v-model="form.modelname" placeholder="请选择拟合类型" @change="selectmodel">
                <el-option v-for="(item, index) in model" :key="index" :value="item.modelname" :label="item.modelshow">{{ item.modelshow }}</el-option>
              </el-select>
            </el-col>
            <el-col class="line" :span="2">-</el-col>
            <el-col :span="10">
              <el-select v-model="form.deg" placeholder="请选择拟合维度" style="width: 100%;">
                <el-option v-for="(item, index) in deg" :key="index" :value="item">{{ item }}</el-option>
              </el-select>
            </el-col>
          </el-form-item>
          <el-form-item v-show="iscustom" label="拟合公式" placeholder="请输入自定义拟合公式，如y=ax+b">
            <el-input v-model="form.iformulas" />
          </el-form-item>
          <el-form-item v-show="ismethod" label="插值方法">
            <el-select v-model="form.method" placeholder="请选择插值方法">
              <el-option v-for="(item, index) in method" :key="index" :value="item">{{ item }}</el-option>
            </el-select>
          </el-form-item>

          <el-divider content-position="left">拟合选项</el-divider>
          <div class="result-box" style="padding:20px">
            <el-form-item label="Normalize">
              <el-select v-model="form.normalize" placeholder="归一化(Normalize)" style="width: 100%;">
                <el-option value="" label="Off">Off</el-option>
                <el-option value="1" label="On">On</el-option>
              </el-select>
            </el-form-item>
            <el-form-item v-show="nonlinear & linear" label="Robust">
              <el-select v-model="form.robust" placeholder="鲁棒性(Robust)" style="width: 100%;">
                <el-option value="" label="Off">Off</el-option>
                <el-option value="LAR" label="On">On</el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="Exclude">
              <el-select v-model="form.exclude" placeholder="数据排除(Exclude)" style="width: 100%;">
                <div v-for="(item, index) in variables" :key="index">
                  <el-option v-if="matchState(item.Type)" :value="item.value" :label="item.Name">{{ item.Name }}</el-option>
                </div>
              </el-select>
            </el-form-item>
            <el-form-item v-show="linear | smooth" label="Weight">
              <el-select v-model="form.weight" placeholder="数据权重(weights)" style="width: 100%;">
                <div v-for="(item, index) in variables" :key="index">
                  <el-option v-if="matchState(item.Type)" :value="item.value" :label="item.Name">{{ item.Name }}</el-option>
                </div>
              </el-select>
            </el-form-item>
            <el-form-item v-show="linear" label="Lower">
              <el-input v-model="form.lower" placeholder="拟合下限(Lower)" />
            </el-form-item>
            <el-form-item v-show="linear" label="Upper">
              <el-input v-model="form.upper" placeholder="拟合上限(Upper)" />
            </el-form-item>
            <el-form-item v-show="nonlinear & linear" label="Startpoint">
              <el-input v-model="form.startpoint" placeholder="拟合系数起始值(Startpoint)" />
            </el-form-item>
            <el-form-item v-show="nonlinear & linear" label="Alogrithm">
              <el-select v-model="form.alogrithm" placeholder="算法(Alogrithm)" style="width: 100%;">
                <el-option value="Trust-Region" label="Trust-Region">Trust-Region</el-option>
                <el-option value="Levenberg-Marquardt" label="Levenberg-Marquardt">Levenberg-Marquardt</el-option>
              </el-select>
            </el-form-item>
            <el-form-item v-show="nonlinear & linear" label="Diffchange">
              <el-input v-model="form.diffchange" placeholder="雅可比矩阵的有限差分近似的步长(Diffchange)" />
            </el-form-item>
            <el-form-item v-show="nonlinear & linear" label="MaxFunEvals">
              <el-input v-model="form.maxfunEvals" placeholder="允许函数最大评估次数(MaxFunEvals)" />
            </el-form-item>
            <el-form-item v-show="nonlinear & linear" label="ToFun">
              <el-input v-model="form.tofun" placeholder="函数值的停止条件的终止公差(ToFun)" />
            </el-form-item>
            <el-form-item v-show="nonlinear & linear" label="Tolx">
              <el-input v-model="form.tolx" placeholder="系数的停止条件的终止公差(Tolx)" />
            </el-form-item>
            <el-form-item v-show="smooth" label="平滑系数">
              <el-input v-model="form.smoothingparam" placeholder="平滑样条系数(smoothingparam)" />
            </el-form-item>
            <el-form-item v-show="smooth" label="平滑系数">
              <el-input v-model="form.smoothingdeg" placeholder="平滑样条曲线阶数(smoothingdeg)" />
            </el-form-item>

          </div>
          <el-form-item style="padding: 20px">
            <el-button type="primary" @click="onSubmit">拟合(fit)</el-button>
          </el-form-item>
        </el-form>
      </el-col>

      <el-col :span="14">
        <h2>拟合结果</h2>
        <!-- <p>{{ msg }}</p> -->
        <div class="result-box">
          <p v-show="!isshow">未进行曲线拟合</p>
          <div v-show="isshow" style="line-height:50%">
            <p> 拟合公式: </p>
            <p>{{ "\xa0\xa0\xa0\xa0\xa0\xa0" }}y = {{ fitresult.formulas }}</p>
            <p>-----------------------------------------------------------------</p>
            <p> 拟合参数(Coefficient) </p>
            <p v-for="(item, index) in fitresult.paras" :key="index">{{ "\xa0\xa0\xa0\xa0\xa0\xa0" }}{{ item }}={{ fitresult.popt[index] }}<br></p>
            <p>-----------------------------------------------------------------</p>
            <p> 拟合优度统计(Godness) </p>
            <p v-for="(item, index) in fitresult.gof" :key="index">{{ "\xa0\xa0\xa0\xa0\xa0\xa0" }}{{ gof_name[index] }}={{ item }}<br></p>
            <p>-----------------------------------------------------------------</p>
            <p> 拟合详细算法信息 </p>
            <p v-for="(item,index) in fitresult.introalg" :key="index">{{ "\xa0\xa0\xa0\xa0\xa0\xa0" }}{{ item }}<br></p>
          </div>
        </div>
        <h2>拟合曲线</h2>
        <p id="tester" style="width:800px; height:360px;" />
        <!-- <div class='result-box'>
          <p v-show='!isshow'>未进行曲线拟合</p>
          <img :src="'data:image/png;base64,' + fitresult.polt" v-show='isshow'>
        </div> -->
      </el-col>
    </el-row>
  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'
import axios from 'axios';
import Plotly from 'plotly.js-dist-min';
export default {
  data() {
    return {
      isshow: false,
      iscustom: false,
      nonlinear: true,
      ismethod: false,
      linear: true,
      smooth: false,
      msg: '',
      x: [],
      y: [],
      fitresult: {
        'gof': [],
        'popt': [],
        'paras': [],
        'introalg': [],
        'formulas': '',
        'yr': [],
        'xr': []
      },
      gof_name: ['SSE', 'R-Square', 'MSE'],
      form: {
        xdata: '',
        ydata: '',
        modelname: '',
        deg: '',
        iformulas: '',
        method: '',
        normalize: '',
        exclude: null,
        robust: '',
        weight: null,
        upper: null,
        lower: null,
        startpoint: null,
        algorithm: 'Trust-Region',
        diffchange: null,
        maxfunEvals: null,
        tofun: 1e-8,
        tolx: 1e-8,
        smoothingparam: null,
        smoothingdeg: '3'
      },
      // 列表关联
      model: [
        {
          modelname: 'poly',
          'modelshow': 'Polynimal',
          deg: ['1', '2', '3', '4', '5', '6', '7', '8', '9']
        },
        {
          modelname: 'exp',
          'modelshow': 'Exptional',
          deg: ['1', '2']
        },
        {
          modelname: 'fourier',
          'modelshow': 'Fourier',
          deg: ['1', '2', '3', '4', '5', '6', '7', '8']
        },
        {
          modelname: 'guass',
          'modelshow': 'Guassian',
          deg: ['1', '2', '3', '4', '5', '6', '7', '8']
        },
        {
          modelname: 'power',
          'modelshow': 'Power',
          deg: ['1', '2']
        },
        {
          modelname: 'sin',
          'modelshow': 'Sum of Sine',
          deg: ['1', '2', '3', '4', '5', '6', '7', '8']
        },
        {
          modelname: 'weibull',
          'modelshow': 'Distribution',
          deg: []
        },
        {
          modelname: 'custom',
          'modelshow': 'Custom',
          deg: []
        },
        {
          modelname: 'Interpolant',
          'modelshow': 'Interpolant',
          deg: [],
          method: ['LinearInterpolant', 'NearestInterpolant', 'PchipInterpolant', 'CubicSplineInterpolant']
        },
        {
          modelname: 'SmoothingSpline',
          'modelshow': 'SmoothingSpline',
          deg: []
        }
      ],
      deg: [],
      method: []
    };
  },
  computed: {
    variables: function() {
      return this.$store.getters['matlab/getProcessedVariables'];
    }
  },
  created() {
    this.getMessage();
  },
  methods: {
    // 传入数据类型判断
    matchState(value) {
      const datastype = ['Arra'];
      if (datastype.includes(value.substring(0, 4))) {
        return true;
      } else {
        return false;
      }
    },
    // 列表静态关联
    selectmodel(value) {
      const _this = this;
      this.model.forEach(function(item) {
        if (item.modelname === value) {
          _this.modelname = item.modelname;
          _this.deg = item.deg;
          _this.form.deg = _this.deg[0];
          if (_this.modelname === 'custom') {
            _this.iscustom = true;
          } else {
            _this.iscustom = false;
          }
          if (_this.modelname === 'poly') {
            _this.nonlinear = false;
          } else {
            _this.nonlinear = true;
          }
          if (_this.modelname === 'Interpolant') {
            _this.method = item.method;
            _this.form.method = _this.method[0];
            _this.ismethod = true;
            _this.linear = false;
          } else {
            _this.ismethod = false;
            _this.linear = true;
          }
          if (_this.modelname === 'SmoothingSpline') {
            _this.smooth = true;
            _this.linear = false;
          }
        }
      });
    },
    // 与后端获取信息
    getMessage() {
      // const path = 'https://service-e5fca2j0-1307736509.gz.apigw.tencentcs.com/release/';
      // const pathlist = 'https://1658038451089714.cn-shenzhen.fc.aliyuncs.com/2016-08-15/proxy/Fits.LATEST/fittoolbox/';
      const pathlist = 'https://1255423045949708.cn-shenzhen.fc.aliyuncs.com/2016-08-15/proxy/cftool.LATEST/fittool/';
      axios
        .get(pathlist)
        .then(res => {
          // console.log(res);
          this.msg = res.status;
        })
        .catch(error => {
          console.error(error);
        });
    },
    // 表单提交
    addfitform(payload) {
      const pathlist = 'https://1255423045949708.cn-shenzhen.fc.aliyuncs.com/2016-08-15/proxy/cftool.LATEST/fittool/';
      axios
        .post(pathlist, payload, { headers: { 'Content-Type': 'application/json;charset=utf8' }})
        .then((res) => {
          this.fitresult = res.fitdata;
          this.plot();
          this.getMessage();
          this.initForm();
        })
        .catch(error => {
          console.error(error);
          this.plot();
          this.getMessage();
          this.initForm();
        });
    },
    initForm() {
      this.form.xdata = '';
      this.form.ydata = '';
      this.form.modelname = '';
      this.form.deg = '';
    },
    // 表单按钮绑定
    onSubmit(evt) {
      evt.preventDefault();
      const payload = {
        xdata: this.form.xdata,
        ydata: this.form.ydata,
        modelname: this.form.modelname,
        deg: this.form.deg,
        iformulas: this.form.iformulas,
        method: this.form.method,
        normalize: this.form.normalize,
        exclude: this.form.exclude,
        weight: this.form.weight,
        robust: this.form.robust,
        upper: this.form.upper,
        lower: this.form.lower,
        tofun: this.form.tofun,
        tolx: this.form.tolx,
        smoothingparam: this.form.smoothingparam,
        smoothingdeg: this.form.smoothingdeg
      };
      // console.log(payload);
      this.addfitform(payload);
      this.isshow = true;
    },
    // 拟合点显现
    plotdot() {
      if (this.form.xdata != null && this.form.ydata != null) {
        this.x = this.form.xdata;
        this.y = this.form.ydata;
        // this.x = this.x.map(Number);
        // this.y = this.form.ydata.slice(1, this.form.ydata.length - 1).split(',');
        // this.y = this.y.map(Number);
        var graphDiv = document.getElementById('tester');
        var trace1 = {
          x: this.x[0],
          y: this.y[0],
          mode: 'markers',
          name: '原始拟合数据',
          marker: {
            color: 'rgb(65, 105, 225)',
            size: 10
          }
        };
        var data = [trace1];
        var layout = {
          showlegend: false,
          xaxis: {
            title: 'x',
            // showgrid: false,
            zeroline: false
          },
          yaxis: {
            title: 'Y'
            // showline: false
          }
        };
        Plotly.newPlot(graphDiv, data, layout, { scrollZoom: true });
      }
    },
    // 拟合曲线绘制
    plot() {
      var graphDiv = document.getElementById('tester');
      var trace1 = {
        x: this.x[0],
        y: this.y[0],
        mode: 'markers',
        name: '原始拟合数据',
        marker: {
          color: 'rgb(65, 105, 225)',
          size: 10
        }
      };
      var trace2 = {
        x: this.fitresult.xr,
        y: this.fitresult.yr,
        type: 'scatter',
        name: '拟合曲线'
      };
      var data = [trace1, trace2];
      var layout = {
        title: '曲线拟合结果',
        xaxis: {
          title: 'X轴',
          // showgrid: false,
          zeroline: false
        },
        yaxis: {
          title: 'Y轴',
          showline: false
        }
      };
      Plotly.newPlot(graphDiv, data, layout);
    }
  }
};
</script>

<style>
.result-box{
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  max-height: 200px;
  min-height: 180px;
  overflow:auto
}
</style>
